package com.ncwu.infrastructure.shirorealm;

import com.ncwu.domain.entity.User;
import com.ncwu.domain.mapper.UserMapper;
import com.ncwu.infrastructure.common.Constant;
import com.ncwu.infrastructure.exception.ErrorEnum;
import com.ncwu.infrastructure.shirotoken.CustomizedToken;
import com.ncwu.infrastructure.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;

/**
 * @Date: 2021/9/8 20:34
 * @Description:
 */
@Slf4j
public class PwdAndCodeRealm extends AuthorizingRealm {
    //认为realm所做的身份认证、权限校验都属于最底部的进入接口前的准备 尽量让其贴近领域层
    @Resource
    private UserMapper userMapper;
    @Resource
    private RedisUtil redisUtil;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof CustomizedToken;
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        log.info("PasswordAndCode权限认证开始,传递的token:{}", authenticationToken);
        //找出数据库中的对象  给定用户输入的对象做出对比
        CustomizedToken token = (CustomizedToken) authenticationToken;
        log.info("PasswordAndCode转换的自定义token是:{}", token);
        // 根据userId查询用户
        User user = userMapper.selectById(token.getUsername());
        if (user == null) {
            // 抛出账号不存在异常
            throw new UnknownAccountException();
        }
        String password = user.getPassword();
        Object code = redisUtil.get(Constant.REDIS_LOGIN_CODE + token.getUsername());
        log.info("redis取出的用户验证码是:{}", code);
        if (code == null) {
            throw new AuthenticationException(ErrorEnum.VERIFICATIONCODE_EXPIRE.getMsg());
        }
        //param1:数据库用户 param2:密码 param3:加密所用盐值 param4:当前realm的名称
        return new SimpleAuthenticationInfo(user, password, ByteSource.Util.bytes(user.getUserId()), getName());
    }
}
